#include "ComponentRandomPeckBehavior.h"
#include "Components/ComponentCreature.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentCreatureSounds.h"
#include "Components/ComponentCreatureModel.h"
#include "ComponentPathfinding.h"

#include "Subsystems/SubsystemTerrain.h"
#include "GameRandom.hpp"
#include "Engine/MathUtils.hpp"
#include "GameSingleton.h"
#include "Log.h"
#include "GameRegistry.hpp"
#include "GameThreadPool.hpp"

#include "Network/PackageManager.h"
#include "Network/Packages/ComponentBehaviorPackage.h"

#include <iostream>

namespace PocketSurvival
{

    // ************** 【状态机】 **************

    ComponentRandomPeckBehavior::StateMachine::StateMachine(ComponentRandomPeckBehavior *lookAroundBehavior) : m_peck(lookAroundBehavior), EasyMachine(MachineState::Inactive) {}

    void ComponentRandomPeckBehavior::StateMachine::enter()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            break;
        case MachineState::Stuck:
            break;
        case MachineState::Move:
            MACHINE_DELEGATE()
            {
                Vector3 position;
                m_peck->componentCreature->componentBody->getPosition(position);

                float num = (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.2f) ? 8.0f : 3.0f;
                Vector3 value = position + Vector3(num * GameSingleton::gameRandom->getFloat(-1.0f, 1.0f), 0.0f, num * GameSingleton::gameRandom->getFloat(-1.0f, 1.0f));
                value.posY = m_peck->terrain->getTopHeight(Terrain::ToCell(value.posX), Terrain::ToCell(value.posZ)) + 1;
                m_peck->componentPathfinding->setDestination(value, GameSingleton::gameRandom->getFloat(0.5f, 0.7f), 1.0f, 0.0f, false, true, false, nullptr);
            }
            break;
        case MachineState::Wait:
            MACHINE_DELEGATE()
            {
                m_peck->m_waitTime = GameSingleton::gameRandom->getFloat(0.75f, 1.0f);
            }
            break;
        case MachineState::Peck:
            MACHINE_DELEGATE()
            {
                m_peck->m_peckTime = GameSingleton::gameRandom->getFloat(2.0f, 6.0f);
            }
            break;
        }
    }

    void ComponentRandomPeckBehavior::StateMachine::update(float dt)
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            if (m_peck->isActive() == true)
            {
                changeTo(MachineState::Move);
            }
            break;
        case MachineState::Stuck:
            MACHINE_DELEGATE()
            {
                changeTo(MachineState::Move);
            }
            break;
        case MachineState::Move:
            MACHINE_DELEGATE()
            {
                if (m_peck->componentPathfinding->destination != FastVector3::Zero)
                {
                    if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.33f)
                    {
                        changeTo(MachineState::Wait);
                    }
                    else
                    {
                        changeTo(MachineState::Peck);
                    }
                }
                else if (m_peck->componentPathfinding->isStuck)
                {
                    changeTo(MachineState::Stuck);
                }
            }
            break;
        case MachineState::Wait:
            MACHINE_DELEGATE()
            {
                m_peck->m_waitTime -= dt;
                if (m_peck->m_waitTime <= 0.0f)
                {
                    if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.25f)
                    {
                        changeTo(MachineState::Move);
                        if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.33f)
                        {
                            // m_peck->componentCreature->componentCreatureSounds->playIdleSound(false);
                        }
                    }
                    else
                    {
                        changeTo(MachineState::Peck);
                    }
                }
            }
            break;
        case MachineState::Peck:
            MACHINE_DELEGATE()
            {
                m_peck->m_peckTime -= dt;
                m_peck->setIsFeed(m_peck->componentCreature->componentBody->standingOnValue != 0);
                if (m_peck->m_peckTime <= 0.0f)
                {
                    if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.25f)
                    {
                        changeTo(MachineState::Move);
                    }
                    else
                    {
                        changeTo(MachineState::Wait);
                    }
                }
            }
            break;
        }
    }

    void ComponentRandomPeckBehavior::StateMachine::leave()
    {
        switch (m_currentState)
        {
        case MachineState::Inactive:
            break;
        case MachineState::Move:
            break;
        case MachineState::Wait:
            break;
        case MachineState::Peck:
            m_peck->setIsFeed(false);
            break;
        }
    }

    // **************************************



    ComponentRandomPeckBehavior::~ComponentRandomPeckBehavior()
    {
        delete m_stateMachine;
    }

    float ComponentRandomPeckBehavior::getImportanceLevel()
    {
        return m_importanceLevel;
    }

    void ComponentRandomPeckBehavior::setIsFeed(bool isFeed)
    {
        if (isFeed != m_isFeed)
        {
            m_isFeed = isFeed;
            GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<ComponentBehaviorPackage>((uint16_t)entity, BehaviorPackageType::RandomPeck, m_isFeed));
        }
    }

    void ComponentRandomPeckBehavior::update(float dt)
    {
        if (GameSingleton::gameRandom->getFloat(0.0f, 1.0f) < 0.033f * dt)
        {
            m_importanceLevel = GameSingleton::gameRandom->getFloat(1.0f, 2.5f);
        }
        if (isActive() == true)
        {
            m_stateMachine->update(dt);
        }
        else
        {
            if (m_stateMachine->currentState() != MachineState::Inactive)
            {
                m_stateMachine->changeTo(MachineState::Inactive);
            }
        }
    }

    static const std::string componentName = "PeckBehavior";
    const std::string &ComponentRandomPeckBehavior::getName() const
    {
        return componentName;
    }
    const std::string &ComponentRandomPeckBehavior::GetName()
    {
        return componentName;
    }
    void ComponentRandomPeckBehavior::load(const nlohmann::json &jsonData)
    {
        componentCreature = GameSingleton::gameRegistry->get<ComponentCreature *>(entity);
        componentPathfinding = GameSingleton::gameRegistry->get<ComponentPathfinding *>(entity);
        terrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();

        m_stateMachine = new StateMachine(this);
    }

}
